package orch

import (
	"github.com/hashicorp/hcl/v2"
)

const MaxLoop = 500

type Step struct {
	Range     hcl.Range
	Name      string
	DependsOn []string
	Index     int
	NeedRun   bool
}

type Group []*Step
type FlowPlan []Group

func (f FlowPlan) NeedRunNumber() int {
	count := 0
	for _, group := range f {
		for _, step := range group {
			if step.NeedRun {
				count++
			}
		}
	}
	return count
}

func (f FlowPlan) HasCycle() (names []*Step) {
	if len(f) == MaxLoop+1 {
		names = make([]*Step, 0)
		for i := len(f) - 1; i >= 0 && len(f[i]) > 0; i-- {
			for _, step := range f[i] {
				names = append(names, step)
			}
		}
	}
	return
}

func (f FlowPlan) MarkModuleRun(moduleName string) {
	for _, group := range f {
		for _, step := range group {
			if step.Name == moduleName {
				step.NeedRun = true
				for _, dep := range step.DependsOn {
					f.MarkModuleRun(dep)
				}
				return
			}
		}
	}
}

func (f FlowPlan) MarkRunAll() {
	for _, group := range f {
		for _, step := range group {
			step.NeedRun = true
		}
	}
}

func newFlow(steps []*Step) FlowPlan {
	preDeps := make([]string, 0)
	for _, p := range steps {
		p.Index = 0
		preDeps = append(preDeps, p.Name)
	}

	var max int
	for max = 0; max < MaxLoop; max++ {
		deps := make([]string, 0)
		for _, p := range steps {
			if has(p.DependsOn, preDeps) {
				p.Index = p.Index + 1
				deps = append(deps, p.Name)
			}
		}

		if len(deps) == 0 {
			break
		}
		preDeps = deps
	}
	flow := FlowPlan{}
	for i := 0; i <= max; i++ {
		group := Group{}
		for _, step := range steps {
			if step.Index == i {
				group = append(group, step)
			}
		}
		flow = append(flow, group)
	}
	return flow
}

func has(a, b []string) bool {
	for _, i := range a {
		for _, j := range b {
			if i == j {
				return true
			}
		}
	}
	return false
}
